# This is a sample Python script.

# Press Shift+F10 to execute it or replace it with your code.
# Press Double Shift to search everywhere for classes, files, tool windows, actions, and settings.
import numpy as np
import cv2
import math

image_path = "images/"
image_name = "img2.jpg"


def power_transformation(image, y, c=1.0):
    """
    图像幂次变换处理函数。不会改变传入图像的数据。

    :param image: 需要处理的图像的数据，是一个numpy数组
    :param y: s = c*r^y 公式中的y。
    :param c: s = c*r^y 公式中的c。默认值为1.0
    :return: 返回值为进行幂次变换后的图像数据，是一个numpy数组。
    """
    process_map = np.arange(256, dtype=image.dtype)
    result = np.copy(image)
    for i in range(0, 255):
        temp = c * pow(i / 255.0, y) * 255
        if temp > 255:
            temp = 255
        if temp < 0:
            temp = 0
        process_map[i] = math.ceil(temp)
    for i in np.nditer(result, op_flags=["readwrite"]):
        i[...] = process_map[i]
    return result


def add_noise(image, rate=0.2):
    """
    为图像添加椒盐噪声函数。该函数不对原图像数据进行更改。

    :param image:  需要添加噪声的图像数据，是一个numpy数组。支持
        一个颜色通道的灰度图像，也支持三个颜色通道的RGB图像
    :param rate:  噪声的比例，值位于0-1之间，值越大，椒盐噪声越多
    :return:  返回添加噪声后的图像数据，是一个numpy数组
    """
    noise_sum = math.floor(image.size * rate)

    image_width = image.shape[1]
    image_height = image.shape[0]

    print("noise_sum:", noise_sum, " image size:", image.size)

    result = np.copy(image)

    for i in range(0, noise_sum):
        ran_col = math.floor(np.random.uniform(0, image_width))
        ran_row = math.floor(np.random.uniform(0, image_height))
        # 处理灰度图像
        if image.ndim == 2:

            result[ran_row, ran_col] = 255
        # 处理RGB图像
        elif image.ndim == 3:
            result[ran_row, ran_col, 0] = 0
            result[ran_row, ran_col, 1] = 0
            result[ran_row, ran_col, 2] = 0
    return result


def mean_filter(image, core):
    """
    均值滤波处理函数。本函数不会修改源图像数据。

    :param image:  需要进行均值滤波操作的图像数据。是一个numpy矩阵
    :param core:  均值滤波的参数。是一个numpy矩阵，其形状（shape）
        决定了均值滤波时特定像素受周围像素影响的范围；其数值决定了周围
        像素对该位置像素的影响权重
    :return:  经过均值滤波后的图像数据，是一个numpy矩阵
    """
    image_width = image.shape[1]
    image_height = image.shape[0]
    core_width = core.shape[0]
    core_height = core.shape[1]
    result = np.copy(image)
    # 生成二通道的图像滤波矩阵
    weight_matrix = np.multiply(1/np.sum(core), core)
    # 生成三通道图像的滤波矩阵
    if image.ndim == 3:
        temp = np.zeros((core_width, core_height, 3))
        for col in range(0, core_width):
            for row in range(0, core_height):
                temp[row, col, :] = np.array([weight_matrix[row, col], weight_matrix[row, col],
                                              weight_matrix[row, col]])
        weight_matrix = temp
    # 对图像进行滤波操作
    for row in range(0, image_height - core_height):
        for col in range(0, image_width - core_width):
            local_matrix = image[row:row+core_height, col:col+core_width]
            temp = np.multiply(weight_matrix, local_matrix)
            mean_value = np.sum(temp, axis=(0, 1))
            result[row, col] = mean_value
    return result


def medium_value_filter(image, window_width=3):
    """
    中值滤波处理函数。本函数不会修改源图像数据，本函数仅支持3通道彩色图像

    :param image: 需要进行均值滤波操作的图像数据。是一个numpy矩阵
    :param window_width: 均值滤波窗口长度，默认为3
    :return: 经过中值滤波后的图像数据，是一个numpy矩阵
    """
    image_width = image.shape[1]
    image_height = image.shape[0]
    result = np.copy(image)
    # 对图像进行中值滤波操作
    for row in range(0, image_height - window_width):
        for col in range(0, image_width - window_width):
            local_matrix = image[row: row+window_width, col:col + window_width]
            local_matrix = local_matrix.reshape(window_width*window_width, image.shape[2])
            result[row, col] = find_medium(local_matrix, window_width)
    return result


def find_medium(data_array, length):
    """
    寻找一个2维数组中第二维之和的中值

    :param length: data_array第一维的长度
    :param data_array: 要寻找中值的二维数组，是一个numpy数组
    :return: 寻找到的中值元素
    """
    mid_position = length//2
    # print("未排序前:", data_array)
    sum_matrix = np.sum(data_array, axis=1)
    # print("求和后:", sum_matrix)
    sorted_matrix = np.sort(sum_matrix)
    # print("排序后:", sorted_matrix)
    mid = np.argwhere(sum_matrix == sorted_matrix[mid_position])
    # print("找到中值的位置:", mid)
    return data_array[mid[0][0]]


def two_divide(image, threshold: float):
    """
    普通阈值分割函数，按照threshold的作为阈值进行阈值分割。该函数不会改变源图像数据。
    此函数可以处理三通道的彩色图像和一通道的灰度图像。

    :param image: 待分割的图像数据
    :param threshold: 分割中的阈值参数。低于此值的函数将被设置为0,。
    :return: 二值分割后的图像。
    """
    image_width = image.shape[1]
    image_height = image.shape[0]
    result = np.zeros((image_height, image_width), np.uint8)
    if image.ndim == 3:
        for row in range(0, image_height):
            for col in range(0, image_width):
                mean = np.sum(image[row][col])/3.0
                if mean > threshold:
                    mean = 255
                else:
                    mean = 0
                result[row][col] = np.uint8(mean)
    elif image.ndim == 2:
        for row in range(0, image_height):
            for col in range(0, image_width):
                mean = image[row][col]
                if mean > threshold:
                    mean = 255
                else:
                    mean = 0
                result[row][col] = np.uint8(mean)
    return result


def minimum_value_filter(image, window_width=3):
    """
    最小值滤波处理函数。本函数不会修改源图像数据，本函数仅支持3通道彩色图像

    :param image: 需要进行均值滤波操作的图像数据。是一个numpy矩阵
    :param window_width: 最小值滤波窗口长度，默认为3
    :return: 经过最小滤波后的图像数据，是一个numpy矩阵
    """
    image_width = image.shape[1]
    image_height = image.shape[0]
    result = np.copy(image)
    # 对图像进行最小值滤波操作
    for row in range(0, image_height - window_width):
        for col in range(0, image_width - window_width):
            local_matrix = image[row: row + window_width, col:col + window_width]
            local_matrix = local_matrix.reshape(window_width * window_width, image.shape[2])
            sum_matrix = np.sum(local_matrix, axis=1)
            sorted_matrix = np.sort(sum_matrix)
            mid = np.argwhere(sum_matrix == sorted_matrix[0])
            result[row, col] = sorted_matrix[mid[0][0]]
    return result

def max_value_filter(image, window_width=3):
    """
    最大值滤波处理函数。本函数不会修改源图像数据，本函数仅支持3通道彩色图像

    :param image: 需要进行最大值滤波操作的图像数据。是一个numpy矩阵
    :param window_width: 最大值滤波窗口长度，默认为3
    :return: 经过最大值滤波后的图像数据，是一个numpy矩阵
    """
    image_width = image.shape[1]
    image_height = image.shape[0]
    result = np.copy(image)
    # 对图像进行最小值滤波操作
    for row in range(0, image_height - window_width):
        for col in range(0, image_width - window_width):
            local_matrix = image[row: row + window_width, col:col + window_width]
            local_matrix = local_matrix.reshape(window_width * window_width, image.shape[2])
            sum_matrix = np.sum(local_matrix, axis=1)
            sorted_matrix = np.sort(sum_matrix)
            mid = np.argwhere(sum_matrix == sorted_matrix[window_width*window_width-1])
            result[row, col] = sorted_matrix[mid[0][0]]
    return result


def brighten(image, alpha=1.0, beta=20):
    """
    图像亮度提升函数

    :param image: 需要提升亮度的图像数据
    :param alpha: 对比度
    :param beta: 亮度提升比例
    :return: 提升亮度后的图像数据
    """
    new_image = np.copy(image)
    for y in range(image.shape[0]):
        for x in range(image.shape[1]):
            for c in range(image.shape[2]):
                new_image[y, x, c] = np.clip(alpha * image[y, x, c] + beta, 0, 255)
    return new_image

if __name__ == '__main__':

    # 读取源图像并显示图像
    image_data = cv2.imread(image_path + image_name, cv2.IMREAD_COLOR)
    cv2.imshow("source_image", image_data)

    #  对图像进行幂次变换
    # processed_image_data = power_transformation(image_data, 0.7)
    # cv2.imshow("processed_image", processed_image_data)
    '''
    # 为图像添加椒盐噪声
    print("start add noise...")
    processed_image_data = add_noise(image_data, 0.002)
    cv2.imshow("noise_image", processed_image_data)

    # 对椒盐图像进行均值滤波
 '''

    

    # 对椒盐图像进行中值滤波
    print("start medium filter process...")
    medium_value_image_data = medium_value_filter(image_data, 3)
    cv2.imshow("medium_value_image_data", medium_value_image_data)

    brighten_image_data = brighten(medium_value_image_data, beta=50)
    cv2.imshow("brighten_image_data", brighten_image_data)
    """
    max_image_data = max_value_filter(brighten_image_data)
    cv2.imshow("max_image_data", brighten_image_data)

    print("start mean filter process...")
    mean_core = np.array([[1, 1, 1], [1, 1, 1], [1, 1, 1]])
    mean_image_data = mean_filter(medium_value_image_data, mean_core)
    cv2.imshow("mean_value_image", mean_image_data)
    """


    """
    # 使用简单阈值分割处理图像
    print("start image fragment using simple threshold...")
    two_divide_image = two_divide(image_data, 222)
    cv2.imshow("two_divide_image", two_divide_image)
    
    print("start minimum filter process...")
    minimum_value_image_data = minimum_value_filter(image_data, 2)
    cv2.imshow("minium_value_image_data", minimum_value_image_data)
    """
    # cv2.GaussianBlur(mean_image_data, (5, 5), 0, mean_image_data)

    kernel = np.array([[0, -1, 0], [-1, 5.1, -1], [0, -1, 0]], np.float32)  # 定义一个核
    dst = cv2.filter2D(brighten_image_data, -1, kernel=kernel)

    cv2.imshow("gaussianBlur", dst)

    print("Finish")
    while True:
        cv2.waitKey(0)

